home *** CD-ROM | disk | FTP | other *** search
/ AGA Toolkit '97 / The AGA Toolkit '97.iso / miscellaneous / science / maths / calc / source / symbol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-07  |  10.9 KB  |  505 lines

  1. /*
  2.  * Copyright (c) 1994 David I. Bell
  3.  * Permission is granted to use, distribute, or modify this source,
  4.  * provided that this copyright notice remains intact.
  5.  *
  6.  * Modified for the Amiga by Steve Leblanc, Oct 1995
  7.  *
  8.  * Global and local symbol routines.
  9.  */
  10.  
  11. #include "calc.h"
  12. #include "token.h"
  13. #include "symbol.h"
  14. #include "string.h"
  15. #include "opcodes.h"
  16. #include "func.h"
  17.  
  18. #define HASHSIZE    37    /* size of hash table */
  19.  
  20.  
  21. static int filescope;        /* file scope level for static variables */
  22. static int funcscope;        /* function scope level for static variables */
  23. static STRINGHEAD localnames;    /* list of local variable names */
  24. static STRINGHEAD globalnames;    /* list of global variable names */
  25. static STRINGHEAD paramnames;    /* list of parameter variable names */
  26. static GLOBAL *globalhash[HASHSIZE];    /* hash table for globals */
  27.  
  28. static void fitprint MATH_PROTO((NUMBER *num, long digits, long width));
  29. static void unscope MATH_PROTO((void));
  30.  
  31.  
  32. /*
  33.  * Hash a symbol name so we can find it in the hash table.
  34.  * Args are the symbol name and the symbol name size.
  35.  */
  36. #define HASHSYM(n, s) ((unsigned)((n)[0]*123 + (n)[s-1]*135 + (s)*157) % HASHSIZE)
  37.  
  38.  
  39. /*
  40.  * Initialize the global symbol table.
  41.  */
  42. void
  43. initglobals()
  44. {
  45.     int i;        /* index counter */
  46.  
  47.     for (i = 0; i < HASHSIZE; i++)
  48.         globalhash[i] = NULL;
  49.     initstr(&globalnames);
  50.     filescope = SCOPE_STATIC;
  51.     funcscope = 0;
  52. }
  53.  
  54.  
  55. /*
  56.  * Define a possibly new global variable which may or may not be static.
  57.  * If it did not already exist, it is created with a value of zero.
  58.  * The address of the global symbol structure is returned.
  59.  */
  60. GLOBAL *
  61. addglobal(name, isstatic)
  62.     char *name;        /* name of global variable */
  63.     BOOL isstatic;        /* TRUE if symbol is static */
  64. {
  65.     GLOBAL *sp;        /* current symbol pointer */
  66.     GLOBAL **hp;        /* hash table head address */
  67.     long len;        /* length of string */
  68.     int newfilescope;    /* file scope being looked for */
  69.     int newfuncscope;    /* function scope being looked for */
  70.  
  71.     newfilescope = SCOPE_GLOBAL;
  72.     newfuncscope = 0;
  73.     if (isstatic) {
  74.         newfilescope = filescope;
  75.         newfuncscope = funcscope;
  76.     }
  77.     len = strlen(name);
  78.     if (len <= 0)
  79.         return NULL;
  80.     hp = &globalhash[HASHSYM(name, len)];
  81.     for (sp = *hp; sp; sp = sp->g_next) {
  82.         if ((sp->g_len == len) && (strcmp(sp->g_name, name) == 0)
  83.             && (sp->g_filescope == newfilescope)
  84.             && (sp->g_funcscope == newfuncscope))
  85.                 return sp;
  86.     }
  87.     sp = (GLOBAL *) malloc(sizeof(GLOBAL));
  88.     if (sp == NULL)
  89.         return sp;
  90.     sp->g_name = addstr(&globalnames, name);
  91.     sp->g_len = len;
  92.     sp->g_filescope = newfilescope;
  93.     sp->g_funcscope = newfuncscope;
  94.     sp->g_value.v_num = qlink(&_qzero_);
  95.     sp->g_value.v_type = V_NUM;
  96.     sp->g_next = *hp;
  97.     *hp = sp;
  98.     return sp;
  99. }
  100.  
  101.  
  102. /*
  103.  * Look up the name of a global variable and return its address.
  104.  * Since the same variable may appear in different scopes, we search
  105.  * for the one with the highest function scope value within the current
  106.  * file scope level (or which is global).  Returns NULL if the symbol
  107.  * was not found.
  108.  */
  109. GLOBAL *
  110. findglobal(name)
  111.     char *name;        /* name of global variable */
  112. {
  113.     GLOBAL *sp;        /* current symbol pointer */
  114.     GLOBAL *bestsp;        /* found symbol with highest scope */
  115.     long len;        /* length of string */
  116.  
  117.     bestsp = NULL;
  118.     len = strlen(name);
  119.     for (sp = globalhash[HASHSYM(name, len)]; sp; sp = sp->g_next) {
  120.         if ((sp->g_len != len) || strcmp(sp->g_name, name))
  121.             continue;
  122.         if (sp->g_filescope == SCOPE_GLOBAL) {
  123.             if (bestsp == NULL)
  124.                 bestsp = sp;
  125.             continue;
  126.         }
  127.         if (sp->g_filescope != filescope)
  128.             continue;
  129.         if ((bestsp == NULL) || (sp->g_funcscope > bestsp->g_funcscope))
  130.             bestsp = sp;
  131.     }
  132.     return bestsp;
  133. }
  134.  
  135.  
  136. /*
  137.  * Return the name of a global variable given its address.
  138.  */
  139. char *
  140. globalname(sp)
  141.     GLOBAL *sp;        /* address of global pointer */
  142. {
  143.     if (sp)
  144.         return sp->g_name;
  145.     return "";
  146. }
  147.  
  148.  
  149. /*
  150.  * Show the value of all global variables, typing only the head and
  151.  * tail of very large numbers.  Only truly global symbols are shown.
  152.  */
  153. void
  154. showglobals()
  155. {
  156.     GLOBAL **hp;            /* hash table head address */
  157.     register GLOBAL *sp;        /* current global symbol pointer */
  158.     long count;            /* number of global variables shown */
  159.     NUMBER *num, *den;
  160.     long digits;
  161.  
  162.     count = 0;
  163.     for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
  164.         for (sp = *hp; sp; sp = sp->g_next) {
  165.             if (sp->g_value.v_type != V_NUM)
  166.                 continue;
  167.             if (sp->g_filescope != SCOPE_GLOBAL)
  168.                 continue;
  169.             if (count++ == 0) {
  170.                 printf("\nName    Digits  Value\n");
  171.                 printf(  "----    ------  -----\n");
  172.             }
  173.             printf("%-8s ", sp->g_name);
  174.             num = qnum(sp->g_value.v_num);
  175.             digits = qdigits(num);
  176.             printf("%-7ld ", digits);
  177.             fitprint(num, digits, 60L);
  178.             qfree(num);
  179.             if (!qisint(sp->g_value.v_num)) {
  180.                 den = qden(sp->g_value.v_num);
  181.                 digits = qdigits(den);
  182.                 printf("\n    %-6ld /", digits);
  183.                 fitprint(den, digits, 60L);
  184.                 qfree(den);
  185.             }
  186.             printf("\n");
  187.         }
  188.     }
  189.     printf(count ? "\n" : "No global variables defined.\n");
  190. }
  191.  
  192.  
  193. /*
  194.  * Print an integer which is guaranteed to fit in the specified number
  195.  * of columns, using imbedded '...' characters if it is too large.
  196.  */
  197. static void
  198. fitprint(num, digits, width)
  199.     NUMBER *num;        /* number to print */
  200.     long digits, width;
  201. {
  202.     long show, used;
  203.     NUMBER *p, *t, *div, *val;
  204.  
  205.     if (digits <= width) {
  206.         qprintf("%r", num);
  207.         return;
  208.     }
  209.     show = (width / 2) - 2;
  210.     t = itoq(10L);
  211.     p = itoq((long) (digits - show));
  212.     div = qpowi(t, p);
  213.     val = qquo(num, div);
  214.     qprintf("%r...", val);
  215.     qfree(p);
  216.     qfree(div);
  217.     qfree(val);
  218.     p = itoq(show);
  219.     div = qpowi(t, p);
  220.     val = qmod(num, div);
  221.     used = qdigits(val);
  222.     while (used++ < show) printf("0");
  223.     qprintf("%r", val);
  224.     qfree(p);
  225.     qfree(div);
  226.     qfree(val);
  227.     qfree(t);
  228. }
  229.  
  230.  
  231. /*
  232.  * Write all normal global variables to an output file.
  233.  * Note: Currently only simple types are saved.
  234.  * Returns nonzero on error.
  235.  */
  236. int
  237. writeglobals(name)
  238.     char *name;
  239. {
  240.     FILE *fp;
  241.     GLOBAL **hp;            /* hash table head address */
  242.     register GLOBAL *sp;        /* current global symbol pointer */
  243.     int savemode;            /* saved output mode */
  244.  
  245.   /* AMIGA MOD: using fopen rather that f_open */
  246.   fp = fopen(name, "w");
  247.     if (fp == NULL)
  248.         return 1;
  249.     math_setfp(fp);
  250.     for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
  251.         for (sp = *hp; sp; sp = sp->g_next) {
  252.             switch (sp->g_value.v_type) {
  253.                 case V_NUM:
  254.                 case V_COM:
  255.                 case V_STR:
  256.                     break;
  257.                 default:
  258.                     continue;
  259.             }
  260.             math_fmt("%s = ", sp->g_name);
  261.             savemode = math_setmode(MODE_HEX);
  262.             printvalue(&sp->g_value, PRINT_UNAMBIG);
  263.             math_setmode(savemode);
  264.             math_str(";\n");
  265.         }
  266.     }
  267.     math_setfp(stdout);
  268.     if (fclose(fp))
  269.         return 1;
  270.     return 0;
  271. }
  272.  
  273.  
  274. /*
  275.  * Reset the file and function scope levels back to the original values.
  276.  * This is called on errors to forget any static variables which were being
  277.  * defined.
  278.  */
  279. void
  280. resetscopes()
  281. {
  282.     filescope = SCOPE_STATIC;
  283.     funcscope = 0;
  284.     unscope();
  285. }
  286.  
  287.  
  288. /*
  289.  * Enter a new file scope level so that newly defined static variables
  290.  * will have the appropriate scope, and so that previously defined static
  291.  * variables will temporarily be unaccessible.  This should only be called
  292.  * when the function scope level is zero.
  293.  */
  294. void
  295. enterfilescope()
  296. {
  297.     filescope++;
  298.     funcscope = 0;
  299. }
  300.  
  301.  
  302. /*
  303.  * Exit from a file scope level.  This deletes from the global symbol table
  304.  * all of the static variables that were defined within this file scope level.
  305.  * The function scope level is also reset to zero.
  306.  */
  307. void
  308. exitfilescope()
  309. {
  310.     if (filescope > SCOPE_STATIC)
  311.         filescope--;
  312.     funcscope = 0;
  313.     unscope();
  314. }
  315.  
  316.  
  317. /*
  318.  * Enter a new function scope level within the current file scope level.
  319.  * This allows newly defined static variables to override previously defined
  320.  * static variables in the same file scope level.
  321.  */
  322. void
  323. enterfuncscope()
  324. {
  325.     funcscope++;
  326. }
  327.  
  328.  
  329. /*
  330.  * Exit from a function scope level.  This deletes static symbols which were
  331.  * defined within the current function scope level, and makes previously
  332.  * defined symbols with the same name within the same file scope level
  333.  * accessible again.
  334.  */
  335. void
  336. exitfuncscope()
  337. {
  338.     if (funcscope > 0)
  339.         funcscope--;
  340.     unscope();
  341. }
  342.  
  343.  
  344. /*
  345.  * Remove all the symbols from the global symbol table which have file or
  346.  * function scopes larger than the current scope levels.  Their memory
  347.  * remains allocated since their values still actually exist.
  348.  */
  349. static void
  350. unscope()
  351. {
  352.     GLOBAL **hp;            /* hash table head address */
  353.     register GLOBAL *sp;        /* current global symbol pointer */
  354.     GLOBAL *prevsp;            /* previous kept symbol pointer */
  355.  
  356.     for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
  357.         prevsp = NULL;
  358.         for (sp = *hp; sp; sp = sp->g_next) {
  359.             if ((sp->g_filescope == SCOPE_GLOBAL) ||
  360.                 (sp->g_filescope < filescope) ||
  361.                 ((sp->g_filescope == filescope) &&
  362.                     (sp->g_funcscope <= funcscope)))
  363.             {
  364.                 prevsp = sp;
  365.                 continue;
  366.             }
  367.  
  368.             /*
  369.              * This symbol needs removing.
  370.              */
  371.             if (prevsp)
  372.                 prevsp->g_next = sp->g_next;
  373.             else
  374.                 *hp = sp->g_next;
  375.         }
  376.     }
  377. }
  378.  
  379.  
  380. /*
  381.  * Initialize the local and parameter symbol table information.
  382.  */
  383. void
  384. initlocals()
  385. {
  386.     initstr(&localnames);
  387.     initstr(¶mnames);
  388.     curfunc->f_localcount = 0;
  389.     curfunc->f_paramcount = 0;
  390. }
  391.  
  392.  
  393. /*
  394.  * Add a possibly new local variable definition.
  395.  * Returns the index of the variable into the local symbol table.
  396.  * Minus one indicates the symbol could not be added.
  397.  */
  398. long
  399. addlocal(name)
  400.     char *name;        /* name of local variable */
  401. {
  402.     long index;        /* current symbol index */
  403.  
  404.     index = findstr(&localnames, name);
  405.     if (index >= 0)
  406.         return index;
  407.     index = localnames.h_count;
  408.     (void) addstr(&localnames, name);
  409.     curfunc->f_localcount++;
  410.     return index;
  411. }
  412.  
  413.  
  414. /*
  415.  * Find a local variable name and return its index.
  416.  * Returns minus one if the variable name is not defined.
  417.  */
  418. long
  419. findlocal(name)
  420.     char *name;        /* name of local variable */
  421. {
  422.     return findstr(&localnames, name);
  423. }
  424.  
  425.  
  426. /*
  427.  * Return the name of a local variable.
  428.  */
  429. char *
  430. localname(n)
  431.     long n;
  432. {
  433.     return namestr(&localnames, n);
  434. }
  435.  
  436.  
  437. /*
  438.  * Add a possibly new parameter variable definition.
  439.  * Returns the index of the variable into the parameter symbol table.
  440.  * Minus one indicates the symbol could not be added.
  441.  */
  442. long
  443. addparam(name)
  444.     char *name;        /* name of parameter variable */
  445. {
  446.     long index;        /* current symbol index */
  447.  
  448.     index = findstr(¶mnames, name);
  449.     if (index >= 0)
  450.         return index;
  451.     index = paramnames.h_count;
  452.     (void) addstr(¶mnames, name);
  453.     curfunc->f_paramcount++;
  454.     return index;
  455. }
  456.  
  457.  
  458. /*
  459.  * Find a parameter variable name and return its index.
  460.  * Returns minus one if the variable name is not defined.
  461.  */
  462. long
  463. findparam(name)
  464.     char *name;        /* name of parameter variable */
  465. {
  466.     return findstr(¶mnames, name);
  467. }
  468.  
  469.  
  470. /*
  471.  * Return the name of a parameter variable.
  472.  */
  473. char *
  474. paramname(n)
  475.     long n;
  476. {
  477.     return namestr(¶mnames, n);
  478. }
  479.  
  480.  
  481. /*
  482.  * Return the type of a variable name.
  483.  * This is either local, parameter, global, static, or undefined.
  484.  */
  485. int
  486. symboltype(name)
  487.     char *name;        /* variable name to find */
  488. {
  489.     GLOBAL *sp;
  490.  
  491.     if (findlocal(name) >= 0)
  492.         return SYM_LOCAL;
  493.     if (findparam(name) >= 0)
  494.         return SYM_PARAM;
  495.     sp = findglobal(name);
  496.     if (sp) {
  497.         if (sp->g_filescope == SCOPE_GLOBAL)
  498.             return SYM_GLOBAL;
  499.         return SYM_STATIC;
  500.     }
  501.     return SYM_UNDEFINED;
  502. }
  503.  
  504. /* END CODE */
  505.